#include "Relay.h"

#include "inc/hw_memmap.h"
#include "gpio.h"
#include "LED.h"

struct REL_resource_t {
	enum Relays myResource;
	enum Relay_Setting requestorArray[LED_LAST];//LED_SO_8_Flt+1];
	unsigned char count[Relay_Setting_End];
	unsigned char max;
	enum Relay_Setting mySetting;
};
struct Relay_t {
	unsigned char port;
	unsigned char pin;
	enum Relay_Setting setting;
	enum Relay_Setting normalState;
};
enum Relay_Ports {
	ALARM_RELAY_PORT = GPIO_PORT_P9,
	FAULT_RELAY_PORT = GPIO_PORT_P9,
	RELAY_1_PORT = GPIO_PORT_P11,
	RELAY_2_PORT = GPIO_PORT_P11,
	RELAY_3_PORT = GPIO_PORT_P11,
	RELAY_4_PORT = GPIO_PORT_P10
};
enum Relay_Pins {
	ALARM_RELAY_PIN = GPIO_PIN0,
	FAULT_RELAY_PIN = GPIO_PIN4,
	RELAY_1_PIN = GPIO_PIN2,
	RELAY_2_PIN = GPIO_PIN1,
	RELAY_3_PIN = GPIO_PIN0,
	RELAY_4_PIN = GPIO_PIN7
};
struct Relay_t relayArray[Relay_Last];
struct REL_resource_t REL_resourceArray[Relay_Last];

void REL_resourceArray_init(unsigned char max, enum LED_INDEX firstResource);
void Relay_set(enum Relays relay, enum Relay_Setting setting);
enum Relay_Setting Relay_getRequest(enum Relays resourceIndex, enum LED_INDEX requestorIndex);

void REL_resourceArray_init(unsigned char max, enum Relays firstResource)
{
	enum Relays resource;
	enum Relays me = firstResource;
	enum LED_INDEX requestor;
	enum Relay_Setting setting;
	for (resource = Relay_Begin; resource<Relay_Last; resource++)
	{
//		REL_resourceArray[i].myIndex = i;
		REL_resourceArray[resource].myResource = me++;
		REL_resourceArray[resource].mySetting = Relay_Off;
		for (setting=Relay_Setting_Begin; setting<Relay_Setting_End; setting++)
		{
			REL_resourceArray[resource].count[setting] = 0;
		}
		for (requestor=(enum LED_INDEX)0; requestor<LED_LAST; requestor++)
		{
			REL_resourceArray[resource].requestorArray[requestor] = Relay_Off;
			REL_resourceArray[resource].count[Relay_Off]++;
//			REL_resourceArray[i].requestorArray[j] = Relay_Off;
		}
		REL_resourceArray[resource].max = REL_resourceArray[resource].count[Relay_Off];//REL_resourceArray[resource].max = max;
	}
}
enum Relay_Setting Relay_getRequest(enum Relays resourceIndex, enum LED_INDEX requestorIndex)
{
	enum Relay_Setting setting = REL_resourceArray[resourceIndex].requestorArray[requestorIndex];
	return setting;
}
int REL_resourceArray_requestRelay(enum Relays resourceIndex, enum LED_INDEX requestorIndex, enum Relay_Setting newSetting)
{
	enum Relay_Setting lastSetting = REL_resourceArray[resourceIndex].requestorArray[requestorIndex];
	if ((requestorIndex >= LED_LAST))//||(requestorIndex < LED_Begin))
	{
		return -1; // Invalid requestor
	}
	if ((resourceIndex > Relay_Last))//||(resourceIndex < Relay_Begin))
	{
		return -2; // Invalid requestor
	}
	REL_resourceArray[resourceIndex].requestorArray[requestorIndex] = newSetting;
	if (REL_resourceArray[resourceIndex].count[lastSetting] != 0)
	{
		REL_resourceArray[resourceIndex].count[lastSetting]--;
	}
	if (REL_resourceArray[resourceIndex].count[newSetting] != REL_resourceArray[resourceIndex].max)// - 1)
	{
		REL_resourceArray[resourceIndex].count[newSetting]++;
	}
	return 0;
}
int REL_resourceArray_processRELAY(void)
{
	enum Relays resourceIndex;

	for (resourceIndex = Relay_Begin; resourceIndex < Relay_Last; resourceIndex ++)
	{
		if (REL_resourceArray[resourceIndex].count[Relay_On] > 0)
		{
			Relay_set(REL_resourceArray[resourceIndex].myResource, Relay_On);
			REL_resourceArray[resourceIndex].mySetting = Relay_On;
		}
		else
		{
			Relay_set(REL_resourceArray[resourceIndex].myResource, Relay_Off);
			REL_resourceArray[resourceIndex].mySetting = Relay_Off;
		}

//		for (requestorIndex = LED_local_begin ; requestorIndex <= LED_local_end; requestorIndex++)
	//	{
//			REL_resourceArray[resourceIndex].
//		}
//		REL_resourceArray[resourceIndex]
	}

	return 0;
}
void Relay_initHelper(enum Relays relay, unsigned char port, unsigned char pin, enum Relay_Setting normalState)
{
	relayArray[relay].port = port;
	relayArray[relay].pin = pin;
	relayArray[relay].setting = normalState;
	relayArray[relay].normalState = normalState;
	GPIO_setAsOutputPin(relayArray[relay].port, relayArray[relay].pin);
	if (normalState == Relay_Off)
	{
		GPIO_setOutputLowOnPin(relayArray[relay].port, relayArray[relay].pin);
	}
	else
	{
		GPIO_setOutputHighOnPin(relayArray[relay].port, relayArray[relay].pin);
	}
}
void Relay_init(void)
{
	Relay_initHelper(Relay_Alarm, ALARM_RELAY_PORT, ALARM_RELAY_PIN, (enum Relay_Setting)Relay_noAlarm);
	Relay_initHelper(Relay_Fault, FAULT_RELAY_PORT, FAULT_RELAY_PIN, (enum Relay_Setting) Relay_noFault);
	Relay_initHelper(Relay_1, RELAY_1_PORT, RELAY_1_PIN, Relay_Off);
	Relay_initHelper(Relay_2, RELAY_2_PORT, RELAY_2_PIN, Relay_Off);
	Relay_initHelper(Relay_3, RELAY_3_PORT, RELAY_3_PIN, Relay_Off);
	Relay_initHelper(Relay_4, RELAY_4_PORT, RELAY_4_PIN, Relay_Off);
	REL_resourceArray_init(LED_end, Relay_Begin);
}

void Relay_set(enum Relays relay, enum Relay_Setting setting)
{
	if (relayArray[relay].normalState == Relay_On) {
		if (setting == Relay_Off)
		{
			setting = Relay_On;
		}
		else
		{
			setting = Relay_Off;
		}
	}
	if (setting == Relay_On)
	{
		GPIO_setOutputHighOnPin(relayArray[relay].port, relayArray[relay].pin);
		relayArray[relay].setting = Relay_On;
	}
	else
	{
		GPIO_setOutputLowOnPin(relayArray[relay].port, relayArray[relay].pin);
		relayArray[relay].setting = Relay_Off;
	}
}
void Relay_AllOff(void)
{
	enum Relays relay;

	for (relay=(enum Relays)0; relay<Relay_Last; relay++)
	{
		Relay_set(relay, Relay_Off);
	}

}

/*
void Relay_test(void)
{
	GPIO_setAsOutputPin(RELAY_1to3_PORT, RELAY_1_PIN | RELAY_2_PIN | RELAY_3_PIN);
	GPIO_setOutputLowOnPin(RELAY_1to3_PORT, RELAY_1_PIN | RELAY_2_PIN | RELAY_3_PIN);
	GPIO_setOutputHighOnPin(RELAY_1to3_PORT, RELAY_1_PIN);
	GPIO_setOutputHighOnPin(RELAY_1to3_PORT, RELAY_2_PIN);
	GPIO_setOutputHighOnPin(RELAY_1to3_PORT, RELAY_3_PIN);
	GPIO_setOutputLowOnPin(RELAY_1to3_PORT, RELAY_1_PIN | RELAY_2_PIN | RELAY_3_PIN);

	GPIO_setAsOutputPin(RELAY_4_PORT, RELAY_4_PIN);
	GPIO_setOutputLowOnPin(RELAY_4_PORT, RELAY_4_PIN);
	GPIO_setOutputHighOnPin(RELAY_4_PORT, RELAY_4_PIN);
	GPIO_setOutputLowOnPin(RELAY_4_PORT, RELAY_4_PIN);
}
*/
